package com.tools.bitbucket.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.tools.bitbucket.config.BitbucketConfig;
import com.tools.bitbucket.pojo.BitbucketProject;
import com.tools.bitbucket.pojo.BitbucketRepository;
import com.tools.bitbucket.pojo.CloneObject;
import com.tools.bitbucket.pojo.LinkObject;
import com.tools.bitbucket.utils.FileUtils;
import com.tools.bitbucket.utils.HttpUtils;
import com.tools.bitbucket.utils.MailUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import javax.mail.internet.InternetAddress;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Future;

@Component
@Slf4j
public class BackUpAsyncService {
    //"http://{bitbucketUrl}/rest/api/1.0/projects/{repositoryName}/repos?limit=1000";
    private static final String PROJECT_URL = "http://%s/rest/api/1.0/projects/%s/repos?limit=1000";
    @Autowired
    private BitbucketConfig bitbucketConfig;

    @Async("threadPoolTaskExecutor")
    public Future<Boolean> getRepository(BitbucketProject bitbucketProject, List<BitbucketProject> bitbucketProjectJsonList, List<BitbucketProject> bitbucketRepositoryBitbucketList) {
        //对配置文件中指定的备份项目，进行过滤
        BitbucketProject backUpBitbucketProject = null;
        if (null != bitbucketConfig.getBackUpProjects() && bitbucketConfig.getBackUpProjects().size() > 0) {
            Optional<BitbucketProject> backUpOptional = bitbucketConfig.getBackUpProjects().stream().filter(backUp -> {
                if (StringUtils.isNotEmpty(backUp.getKey())) {
                    return bitbucketProject.getKey().equals(backUp.getKey());
                }
                if (StringUtils.isNotEmpty(backUp.getName())) {
                    return bitbucketProject.getName().equals(backUp.getName());
                }
                return false;
            }).findFirst();
            if (backUpOptional.isPresent()) {
                backUpBitbucketProject = backUpOptional.get();
            } else {
                log.warn("{} 项目已跳过备份", bitbucketProject.getName());
                return new AsyncResult<Boolean>(Boolean.TRUE);//跳过该仓库
            }
        }
        //通过判断该项目目录是否存在，维护该项目是否为历史项目，若存在该项目目录，则为历史备份项目，不存在则为新增备份项目
        if (FileUtils.directoryExists(bitbucketConfig.getBackUpPath() + File.separator + bitbucketProject.getName())) {
            Optional<BitbucketProject> firstRepositoryOptional = bitbucketProjectJsonList.stream().filter(bitbucketProject1 -> bitbucketProject.getName().equals(bitbucketProject1.getName())).findFirst();
            if (firstRepositoryOptional.isPresent()) {
                BitbucketProject bitbucketProject1 = firstRepositoryOptional.get();
                bitbucketProject1.setExist(Boolean.TRUE);
            } else {
                bitbucketProject.setExist(Boolean.TRUE);
                bitbucketProjectJsonList.add(bitbucketProject);
            }
        } else {
            Optional<BitbucketProject> firstRepositoryOptional = bitbucketProjectJsonList.stream().filter(bitbucketProject1 -> bitbucketProject.getName().equals(bitbucketProject1.getName())).findFirst();
            if (firstRepositoryOptional.isPresent()) {
                BitbucketProject bitbucketProject1 = firstRepositoryOptional.get();
                bitbucketProject1.setExist(Boolean.FALSE);
            } else {
                bitbucketProject.setExist(Boolean.FALSE);
                bitbucketProjectJsonList.add(bitbucketProject);
            }
        }
        //创建仓库目录
        String repositoryPath = FileUtils.crateDir(bitbucketConfig.getBackUpPath(), bitbucketProject.getName());
        if (null != repositoryPath) {
            //创建项目介绍文件
            FileUtils.updateIntroFile(repositoryPath, bitbucketProject.getDescription());
            //获取服务端该项目下的所有仓库
            String strResult = HttpUtils.sendGet(String.format(PROJECT_URL, bitbucketConfig.getBaseUrl(), bitbucketProject.getKey()));
            List<BitbucketRepository> bitbucketRepositoryList = JSON.parseArray(JSON.parseObject(strResult).get("values").toString(), BitbucketRepository.class);
            if (null != bitbucketRepositoryList && bitbucketRepositoryList.size() > 0) {
                BitbucketProject finalBackUpBitbucketProject = backUpBitbucketProject;
                bitbucketRepositoryList.stream().forEach(bitbucketRepositoryObject -> {
                    LinkObject links = bitbucketRepositoryObject.getLinks();
                    if (null != links) {
                        List<CloneObject> cloneObjectList = links.getClone();
                        if (null != cloneObjectList && cloneObjectList.size() > 0) {
                            Optional<CloneObject> projectOptional = cloneObjectList.stream().filter(cloneObject -> "http".equals(cloneObject.getName())).findFirst();
                            if (projectOptional.isPresent()) {
                                //获取 当前项目下每个仓库中克隆地址类型为 http 的克隆地址
                                CloneObject repository = projectOptional.get();
                                //将该仓库 维护至 服务器 项目信息列表中，在备份完成后，进行比较
                                Optional<BitbucketProject> compareRepositoryOptional = bitbucketRepositoryBitbucketList.stream().filter(bitbucketProject1 -> bitbucketProject.getKey().equals(bitbucketProject1.getKey())).findFirst();
                                if (compareRepositoryOptional.isPresent()) {
                                    BitbucketProject compareBitbucketProject = compareRepositoryOptional.get();
                                    if (null == compareBitbucketProject.getRepositoryList() || compareBitbucketProject.getRepositoryList().size() == 0) {
                                        compareBitbucketProject.setRepositoryList(new ArrayList<>());
                                    }
                                    List<CloneObject> compareRepositoryList = compareBitbucketProject.getRepositoryList();
                                    CloneObject cloneObject = new CloneObject();
                                    BeanUtils.copyProperties(repository, cloneObject);
                                    compareRepositoryList.add(cloneObject);
                                    compareBitbucketProject.setRepositoryList(compareRepositoryList);
                                }
                                //同步备份代码，并维护版本信息
                                //过滤 配置文件中需要跳过备份的项目和仓库
                                if (null != bitbucketConfig.getIgnoreProjects() && bitbucketConfig.getIgnoreProjects().size() > 0) {
                                    Optional<BitbucketProject> ignoreRepository = bitbucketConfig.getIgnoreProjects().stream().filter(bitbucketProject1 -> {
                                        if (StringUtils.isNotEmpty(bitbucketProject1.getKey())) {
                                            return bitbucketProject.getKey().equals(bitbucketProject1.getKey());
                                        }
                                        if (StringUtils.isNotEmpty(bitbucketProject1.getName())) {
                                            return bitbucketProject.getName().equals(bitbucketProject1.getName());
                                        }
                                        return false;
                                    }).findFirst();
                                    if (ignoreRepository.isPresent()) {
                                        BitbucketProject bitbucketProject1 = ignoreRepository.get();
                                        if (null != bitbucketProject1.getRepositoryList() && bitbucketProject1.getRepositoryList().size() > 0) {
                                            Optional<CloneObject> ignoreProjectOptional = bitbucketProject1.getRepositoryList().stream().filter(ignoreProject -> {
                                                return ignoreProject.getName().equals(repository.getName()) && ignoreProject.getHref().equals(repository.getHref());
                                            }).findFirst();
                                            if (ignoreProjectOptional.isPresent()) {
                                                log.warn("{} 项目下的 {} 仓库已跳过备份", bitbucketProject1.getName(), FileUtils.getProjectName(ignoreProjectOptional.get().getHref()));
                                                return;//跳过该项目
                                            }
                                        } else {
                                            log.warn("{} 项目已跳过备份", bitbucketProject1.getName());
                                            return;//跳过该仓库
                                        }
                                    }
                                }

                                if (null != finalBackUpBitbucketProject && null != finalBackUpBitbucketProject.getRepositoryList() && finalBackUpBitbucketProject.getRepositoryList().size() > 0) {
                                    Optional<CloneObject> backUpProjectOptional = finalBackUpBitbucketProject.getRepositoryList().stream().filter(backUpPorject -> {
                                        return backUpPorject.getName().equals(repository.getName()) && backUpPorject.getHref().equals(repository.getHref());
                                    }).findFirst();
                                    if (backUpProjectOptional.isPresent()) {
                                        //备份该项目
                                    } else {
                                        return;
                                    }
                                } else {
                                    //备份该仓库下的所有项目
                                }
                                // 执行git命令，进行代码 克隆 或 拉取， 并通过 git rev-parse HEAD 获取最新的commitId
                                String latestCommitId = FileUtils.gitCloneOrPull(repositoryPath, repository.getHref());
                                if (StringUtils.isNotEmpty(latestCommitId)) {
                                    Optional<BitbucketProject> existProjectOptional = bitbucketProjectJsonList.stream().filter(bitbucketProject1 -> bitbucketProject.getName().equals(bitbucketProject1.getName())).findFirst();
                                    if (existProjectOptional.isPresent()) {
                                        BitbucketProject existProject = existProjectOptional.get();
                                        List<CloneObject> repositoryList = existProject.getRepositoryList();
                                        if (null != repositoryList && repositoryList.size() > 0) {
                                            Optional<CloneObject> existRepositoryOptional = repositoryList.stream().filter(cloneObject -> cloneObject.getHref().equals(repository.getHref())).findFirst();
                                            if (existRepositoryOptional.isPresent()) {
                                                CloneObject existRepository = existRepositoryOptional.get();
                                                existRepository.setExist(true);
                                                if (StringUtils.isEmpty(existRepository.getLatestCommitId()) || !existRepository.getLatestCommitId().equals(latestCommitId)) {
                                                    existRepository.setChange(true);
                                                } else {
                                                    existRepository.setChange(false);
                                                }
                                                existRepository.setLatestCommitId(latestCommitId);
                                            } else {
                                                repository.setExist(Boolean.FALSE);
                                                repository.setChange(Boolean.TRUE);
                                                repository.setLatestCommitId(latestCommitId);
                                                repositoryList.add(repository);
                                            }
                                        } else {
                                            ArrayList<CloneObject> newRepositoryList = new ArrayList<>();
                                            repository.setExist(Boolean.FALSE);
                                            repository.setChange(Boolean.TRUE);
                                            repository.setLatestCommitId(latestCommitId);
                                            newRepositoryList.add(repository);
                                            existProject.setRepositoryList(newRepositoryList);
                                        }
                                    }
                                }
                            }
                        }
                    }
                });
            }
        }
        return new AsyncResult<Boolean>(Boolean.TRUE);
    }

    @Async("threadPoolTaskExecutor")
    public void sendMail(List<Future<Boolean>> futureList, List<BitbucketProject> bitbucketProjectJsonList, List<BitbucketProject> bitbucketRepositoryBitbucketList, File latestVersionInfo, InternetAddress fromMail, List<InternetAddress> toMailList) {
        while (true) {
            try {
                //休眠一段时间等待，所有备份线程执行结束
                Thread.sleep(20000);
                Boolean endFlag = true;
                if (null != futureList && futureList.size() > 0) {
                    for (Future<Boolean> future : futureList) {
                        if (null == future || !future.isDone()) {
                            //备份线程尚未执行完毕
                            endFlag = false;
                        }
                    }
                }
                if (!endFlag) {
                    continue;
                }
                if (null != bitbucketProjectJsonList && bitbucketProjectJsonList.size() > 0) {
                    //将同步后的项目备份信息写入文件
                    FileUtils.writerJson(latestVersionInfo, JSONArray.toJSONString(bitbucketProjectJsonList));
                    //组装邮件内容
                    StringBuffer stringBuffer = new StringBuffer();
                    //通过比较服务器项目信息列表 和 完成备份的项目信息列表，获取 那些项目进行了备份，那些项目跳过了备份
                    bitbucketRepositoryBitbucketList.stream().forEach(bitbucketRepositoryBitbucket -> {
                        if (bitbucketProjectJsonList.contains(bitbucketRepositoryBitbucket)) {

                            bitbucketProjectJsonList.stream().filter(bitbucketProject -> bitbucketProject.equals(bitbucketRepositoryBitbucket)).forEach(bitbucketRepository -> {
                                // 组装项目信息
                                if (bitbucketRepository.getExist()) {
                                    // xx 项目为历史项目
                                    stringBuffer.append(String.format("<p></p>%s 项目为历史项目", bitbucketRepository.getName()) + "<br />");
                                } else {
                                    // xx 项目为新增项目
                                    stringBuffer.append(String.format("<p></p><span style='color: red; font-weight: bold'>%s</span> 项目为新增项目", bitbucketRepository.getName()) + "<br />");
                                }
                                // 组装仓库信息
                                if (null != bitbucketRepositoryBitbucket.getRepositoryList() && bitbucketRepositoryBitbucket.getRepositoryList().size() > 0) {
                                    bitbucketRepositoryBitbucket.getRepositoryList().stream().forEach(bitbucketProject -> {
                                        if (null != bitbucketRepository.getRepositoryList() && bitbucketRepository.getRepositoryList().size() > 0) {
                                            if (bitbucketRepository.getRepositoryList().contains(bitbucketProject)) {
                                                bitbucketRepository.getRepositoryList().stream().filter(project -> project.equals(bitbucketProject)).forEach(project -> {
                                                    if (project.getExist()) {
                                                        // xxx 项目下的 xx 仓库为 历史仓库 ，无改动 ，已同步完成，最新的commitId 为 xxx  <span style="color: red; font-weight: bold"></span>
                                                        stringBuffer.append(String.format("&nbsp&nbsp&nbsp&nbsp %s 项目下的 %s 仓库为历史仓库,", bitbucketRepository.getName(), FileUtils.getProjectName(project.getHref())));
                                                    } else {
                                                        // xxx 项目下的 xx 仓库为 新增仓库 ，已克隆完成，最新的commitId 为 xxx
                                                        stringBuffer.append(String.format("&nbsp&nbsp&nbsp&nbsp %s 项目下的 <span style='color: red; font-weight: bold'>%s</span> 仓库为新增仓库,", bitbucketRepository.getName(), FileUtils.getProjectName(project.getHref())));
                                                    }
                                                    if ("HEAD".equals(project.getLatestCommitId())) {
                                                        stringBuffer.append("该仓库为空仓库,尚未上传代码,已跳过备份" + "<br />");
                                                    } else {
                                                        if (project.getChange()) {
                                                            // xxx 项目下的 xx 仓库为 历史仓库 ，有改动 ，已同步完成，最新的commitId 为 xxx
                                                            stringBuffer.append(String.format("<span style='color: red; font-weight: bold'>有改动</span>,已同步完成,最新的commitId为 <span style='color: red; font-weight: bold'>%s</span>", project.getLatestCommitId()) + "<br />");
                                                        } else {
                                                            // xxx 项目下的 xx 仓库为 历史仓库 ，无改动 ，已同步完成，最新的commitId 为 xxx
                                                            stringBuffer.append(String.format("无改动,已同步完成,最新的commitId为 %s", project.getLatestCommitId()) + "<br />");
                                                        }
                                                    }
                                                });
                                            } else {
                                                stringBuffer.append(String.format("&nbsp&nbsp&nbsp&nbsp %s 项目下的 <span style='color: red; font-weight: bold'>%s</span> 仓库 <span style='color: red; font-weight: bold'>已跳过备份</span><br />", bitbucketRepository.getName(), FileUtils.getProjectName(bitbucketProject.getHref())));
                                            }
                                        }
                                    });
                                } else {
                                    stringBuffer.append("&nbsp&nbsp&nbsp&nbsp该项目不在本次备份范围内，已跳过备份<br />");
                                }
                            });
                        } else {
                            stringBuffer.append(String.format("<p></p><span style='color: red; font-weight: bold'>%s</span> 仓库 <span style='color: red; font-weight: bold'>已跳过备份</span>", bitbucketRepositoryBitbucket.getName()) + "<br />");
                        }
                    });
                    log.info(stringBuffer.toString());
                    if (null != toMailList && toMailList.size() != 0) {
                        //发送邮件
                        String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
                        MailUtils.sendMail(fromMail, toMailList, today + " bitbucket代码仓库 备份完成", stringBuffer.toString());
                    }
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}
